package com.sikulifang.bank.simulation.service.bank;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.db.Entity;
import cn.hutool.db.sql.Order;
import cn.hutool.db.sql.SqlBuilder;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.sikulifang.bank.simulation.constant.CodeConstants;
import com.sikulifang.bank.simulation.dto.QueryReceiptDTO;
import com.sikulifang.bank.simulation.dto.ReceiptDTO;
import com.sikulifang.bank.simulation.dto.ResponseReceiptDTO;
import com.sikulifang.bank.simulation.enums.BankEnum;
import com.sikulifang.bank.simulation.util.AsyncUtil;
import com.sikulifang.bank.simulation.util.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.File;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.sikulifang.bank.simulation.constant.TableConstants.DETAIL_TABLE_NAME;
import static com.sikulifang.bank.simulation.constant.TableConstants.RECEIPT_TABLE_NAME;

/**
 * ClassName CMBAccountServiceImplImpl
 * Description 招行
 *
 * @author Yat
 * Date 2023/6/6 16:42
 * version 1.0
 */
@Slf4j
@Service
public class CMBBankMessage extends AbstractBankMessage {

    @Override
    public String bankCode() {
        return BankEnum.CMB.name();
    }

    @Override
    public String getActionName(String message) {
        JSONObject jsonObject = JSONUtil.parseObj(message);

        return Convert.toStr(
                JSONUtil.getByPath(jsonObject, "$.request.head.funcode")
        );
    }

    @Override
    protected String getType(String actionName) {
        return null;
    }

    @Override
    public String inlet(String message) {
        JSONObject jsonObject = JSONUtil.parseObj(message);

        String action = Convert.toStr(
                JSONUtil.getByPath(jsonObject, "$.request.head.funcode")
        );
        return switch (action) {
            case "ASYCALHD" -> queryReceiptInfo(jsonObject);
            case "DCTASKID" -> dowReceipt(jsonObject);
            default -> action;
        };
    }

    /**
     * 查询电子回单
     *
     * @param queryReceipt 查询电子回单的参数
     */
    private R<ResponseReceiptDTO> queryReceipt(QueryReceiptDTO queryReceipt) {

        String accNo = queryReceipt.getAccNo();

        BigDecimal maxAmt = queryReceipt.getMaxAmt();
        BigDecimal minAmt = queryReceipt.getMinAmt();

        String startDate = queryReceipt.getStartDate();
        String endDate = queryReceipt.getEndDate();

        startDate = DateUtil.format(DateUtil.parse(startDate), DatePattern.PURE_DATE_PATTERN);
        endDate = DateUtil.format(DateUtil.parse(endDate), DatePattern.PURE_DATE_PATTERN);


        SqlBuilder builder = SqlBuilder.create().select("*")
                .from(DETAIL_TABLE_NAME)
                .where("status = " + 1)
                .append(" and  bank_code= '" + bankCode() + "'")
                .append(" and  account_no= '" + accNo + "'");

        if (ObjectUtil.isNotNull(minAmt)) {
            builder.append("and money >=" + minAmt);
        }
        if (ObjectUtil.isNotNull(maxAmt)) {
            builder.append("and money <=" + maxAmt);
        }
        if (CharSequenceUtil.isNotBlank(startDate)) {
            builder.append("and tran_date >= '" + startDate + "'");
        }
        if (CharSequenceUtil.isNotBlank(endDate)) {
            builder.append("and tran_date <= '" + endDate + "'");
        }
        builder.orderBy(new Order("id"));


        // 回单编号
        String idStr = IdUtil.getSnowflakeNextIdStr();

        ResponseReceiptDTO dto = new ResponseReceiptDTO();
        try {
            List<Entity> query = db.query(builder.build());
            if (query.isEmpty()) {
                return R.failed(dto, "无回单信息");
            }

            Set<Object> idSet = query.stream()
                    .map(d -> d.get("id"))
                    .collect(Collectors.toSet());
            String idSetJson = JSONUtil.toJsonStr(idSet);

            // 根据查询的明细id，判断当前数据是否生成过
            Entity getEntity = db.get(Entity.create(RECEIPT_TABLE_NAME).set("detail_id", idSetJson));
            if (getEntity != null) {
                dto.setDataStr(getEntity.getStr("receipt_number"));
                return R.ok(dto);
            }

            db.insert(
                    Entity.create(RECEIPT_TABLE_NAME)
                            .set("receipt_number", idStr)
                            .set("detail_id", idSetJson)
                            .set("schedule", 0)
            );

            AsyncUtil.getThreadPoolExecutor().execute(() -> createPdf(query, idStr));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        dto.setDataStr(idStr);

        return R.ok(dto);
    }

    @Override
    public R<Dict> dowReceipt(List<ReceiptDTO> receiptList) {

        try {
            ReceiptDTO receiptDTO = receiptList.get(0);
            Entity where = Entity.create(RECEIPT_TABLE_NAME).set("receipt_number", receiptDTO.getBrSeqNo());
            Entity entity = db.get(where);
            Dict dict = new Dict();
            if (entity == null) {
                return R.failed(dict, "请确认传入的任务ID为查询请求时返回的ID！");
            }

            if (entity.getInt("schedule") == 0) {
                return R.failed(dict, "正在处理");
            } else if (entity.getInt("schedule") == 1) {
                String url = "http://127.0.0.1:3600/file/download?receiptNumber=" + entity.get("receipt_number");
                dict.set("fileurl", url);
                return R.ok(dict);
            } else {
                return R.failed(dict, "回单生成失败");
            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param query 流水 明细
     * @param idStr 回单编号
     */
    @Async
    public void createPdf(List<Entity> query, String idStr) {

        Entity where = Entity.create().set("receipt_number", idStr);

        try {
            // 创建临时目录
            File mkdir = FileUtil.mkdir("/home/tmp/" + IdUtil.objectId() + "/");
            for (Entity entity : query) {
                String pdf = detailService.createPdf(entity);
                FileUtil.copy(FileUtil.file(pdf), mkdir, false);
            }

            File zip = ZipUtil.zip(mkdir);

            Entity schedule = Entity.create(RECEIPT_TABLE_NAME).set("schedule", 1).set("content", zip.getPath());
            db.update(schedule, where);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }


    private String queryReceiptInfo(JSONObject bean) {

        String accNo = Convert.toStr(
                JSONUtil.getByPath(bean, "$.request.body.eacnbr")
        );
        String startDate = Convert.toStr(
                JSONUtil.getByPath(bean, "$.request.body.begdat")
        );
        String endDate = Convert.toStr(
                JSONUtil.getByPath(bean, "$.request.body.enddat")
        );

        BigDecimal minAmt;
        Object begAmt = JSONUtil.getByPath(bean, "$.request.body.begamt");
        if (ObjectUtil.isNotEmpty(begAmt)) {
            minAmt = Convert.toBigDecimal(begAmt);
        } else {
            minAmt = new BigDecimal("0.00");
        }

        BigDecimal maxAmt;
        Object endAmt = JSONUtil.getByPath(bean, "$.request.body.endamt");
        if (ObjectUtil.isNotEmpty(endAmt)) {
            maxAmt = Convert.toBigDecimal(endAmt);
        } else {
            maxAmt = new BigDecimal("9999999999999.99");
        }

        QueryReceiptDTO queryReceipt = new QueryReceiptDTO();
        queryReceipt.setStartDate(startDate);
        queryReceipt.setEndDate(endDate);
        queryReceipt.setAccNo(accNo);
        queryReceipt.setMinAmt(minAmt);
        queryReceipt.setMaxAmt(maxAmt);

        R<ResponseReceiptDTO> data = queryReceipt(queryReceipt);

        String resultmsg = "";

        Dict body = new Dict();

        if (data.getCode() == CodeConstants.SUCCESS) {
            Dict asycalhdz1 = new Dict();
            asycalhdz1.set("rtncod", data.getCode());
            asycalhdz1.set("rtnmsg", "");
            asycalhdz1.set("rtndat", data.getData().getDataStr());

            Dict ctnkeyz2 = new Dict();
            ctnkeyz2.set("begamt", "");
            ctnkeyz2.set("begdat", "2018-01-02");
            ctnkeyz2.set("daltag", "N");
            ctnkeyz2.set("eacnbr", "769900135910504");
            ctnkeyz2.set("endamt", "");
            ctnkeyz2.set("enddat", "2018-01-02");
            ctnkeyz2.set("nxtdat", "2018-01-02");
            ctnkeyz2.set("nxtnbr", "359A000003433");
            ctnkeyz2.set("nxttim", "153321");
            ctnkeyz2.set("oprtyp", "N");
            ctnkeyz2.set("pagcnt", "20");
            ctnkeyz2.set("pattyp", "AS400");
            ctnkeyz2.set("predat", "2018-01-02");
            ctnkeyz2.set("prenbr", "359A000003432");
            ctnkeyz2.set("pretim", "101218");
            ctnkeyz2.set("rrccod", "");
            ctnkeyz2.set("rrcflg", "2");
            ctnkeyz2.set("spc100", "");

            body.set("asycalhdz1", asycalhdz1);
            body.set("ctnkeyz2", ctnkeyz2);

        } else {
            resultmsg = data.getMsg();
        }

        Dict head = new Dict();
        head.set("funcode", "ASYCALHD");
        head.set("reqid", "2019042315180903812656309C23BFE9D1");
        head.set("resultcode", "SUC0000");
        head.set("resultmsg", resultmsg);
        head.set("rspid", "20190423151809124000100180256958-OAPC");
        head.set("userid", "N000097143");


        Dict response = new Dict();
        response.set("body", body);
        response.set("head", head);

        Dict result = new Dict();
        result.set("response", response);
        return JSONUtil.toJsonStr(result);
    }

    private String dowReceipt(JSONObject bean) {
        String taskid = Convert.toStr(
                JSONUtil.getByPath(bean, "$.request.body.taskid")
        );

        ArrayList<ReceiptDTO> receiptDTOS = ListUtil.toList(ReceiptDTO.builder().brSeqNo(taskid).build());
        R<Dict> data = dowReceipt(receiptDTOS);

        Dict body = new Dict();
        if (data.getCode() == 10000) {
            String format = DateUtil.format(new Date(), DatePattern.NORM_DATETIME_PATTERN);
            body.set("fileurl", data.getData().getStr("fileurl"));
            body.set("fintim", format);

        }

        Dict head = new Dict();
        head.set("bizcode", "");
        head.set("funcode", "ASYCALHD");
        head.set("reqid", "202101151036562582247001412100D86193CDB4");
        head.set("resultcode", "SUC0000");
        head.set("resultmsg", data.getMsg());
        head.set("rspid", "20210115103656265000100180374319-LW");
        head.set("userid", "N000086168");


        Dict response = new Dict();
        response.set("body", body);
        response.set("head", head);

        Dict result = new Dict();
        result.set("response", response);
        return JSONUtil.toJsonStr(result);
    }

}
